/* $Id: NeoXMLModelWriter.cs,v 1.11 2005/01/12 06:36:30 larsbm Exp $
 * Copyright (c) 2004 Engine EAR GmbH & Co. KG
 * Developed by: Lars Behrmann, lb@engine.de
 */

using System;
using System.IO;
using System.Data;
using SQLToNeo.PlugIn;

namespace SQLToNeo.Model
{
	/// <summary>
	/// NeoXMLModelWriter
	/// </summary>
	public class NeoXMLModelWriter : IWriter
	{
		private DataSet _ds;
		private StreamWriter _writer;
		private string _name;
		private string _header;
		private string _abbreviation;
		private bool _generateJavaName;

		public NeoXMLModelWriter()
		{
			_name = "Neo XML";
			_abbreviation = "neo";
			_generateJavaName = false;
		}

		private bool WriteHeader()
		{
			SetHeader();
			try
			{
				_writer.Write(_header); 
			}
			catch(Exception ex)
			{
				System.Windows.Forms.MessageBox.Show("Error while writing model in private method WriteHeader()!\n\nMessage:\n"+ex.Message+"\n\nMay be the path & filename you choose is empty or impossible to create ?",
					"Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
				return false;
			}
			return true;
		}

		private bool WriteTable(DataRow tablerow)
		{
			if(tablerow["create"].ToString().Length==0)
				tablerow["create"] = false;
			if(!Convert.ToBoolean(tablerow["create"].ToString()))
				return true;
			string table = @"<table name=""#name#"" javaName=""#javaName#"" idMethod=""#idMethod#"" defaultProperty=""#defaultProperty#"" manyToMany=""#manyToMany#"" description="""">";
			table = table.Replace("#name#",  tablerow["name"].ToString());
			table = table.Replace("#idMethod#",  tablerow["idMethod"].ToString());
			table = table.Replace("#defaultProperty#",  tablerow["defaultProperty"].ToString());
			table = table.Replace("#manyToMany#",  tablerow["manyToMany"].ToString().ToLower());
			table = table.Replace("#javaName#", ((tablerow["javaName"].ToString().Length>0)?tablerow["javaName"].ToString():tablerow["name"].ToString()));
			_writer.WriteLine(table);
			if(!WriteColumns(tablerow))
				return false;
			if(!WriteRelations(tablerow, "foreignkey"))
				return false;
			if(!WriteRelations(tablerow, "iforeignkey"))
				return false;
			_writer.WriteLine("</table>\n\n");
			return true;
		}

		private string ToLeadingCaps( string name )
		{
			char[] chars = name.ToLower().ToCharArray();
			chars[0] = Char.ToUpper( chars[0] );
			return new string( chars );
		}
	
		private string ToCamelCase(string name)
		{
			string[] segs = name.Split('_');
			if (segs.Length > 1)
			{
				string tmp = "";
				foreach (string seg in segs)
				{
					tmp += ToLeadingCaps( seg );
				}
				return tmp;
			}
			else
			{
				return ToLeadingCaps( name );
			}
		}

		private string StripTrailingS(string name)
		{
			if (name.EndsWith("S") || name.EndsWith("s"))
			{
				return name.Substring(0, name.Length - 1);
			}
			else
			{
				return name;
			}
		}

		private bool WriteColumns(DataRow tablerow)
		{			
			try
			{
				foreach(DataRow dr in tablerow.GetChildRows("cols"))
				{
					if(dr["create"].ToString().Length==0)
						dr["create"] = false;
					if(dr["required"].ToString().Length==0)
						dr["required"] = false;
					if(dr["hidden"].ToString().Length==0)
						dr["hidden"] = false;
					if(dr["primarykey"].ToString().Length==0)
						dr["primarykey"] = false;
					if(!Convert.ToBoolean(dr["create"].ToString()))
						continue;
					string column = "\t"+@"<column name=""#name#"" javaName=""#javaName#"" type=""#type#"" required=""#required#"" ";
					try
					{
						column = column.Replace("#name#", dr["name"].ToString());
						column = column.Replace("#javaName#", ((dr["javaName"].ToString().Length>0)?dr["javaName"].ToString():dr["name"].ToString()));
						column = column.Replace("#type#", dr["type"].ToString());
						column = column.Replace("#required#", dr["required"].ToString().ToLower());
						if(Convert.ToBoolean(dr["hidden"].ToString()))
							column += @"hidden=""true"" ";
						if((dr["type"].ToString() == "VARCHAR") || (dr["type"].ToString() == "CHAR"))
							column += "size=\""+dr["size"].ToString()+"\" ";
						if(Convert.ToBoolean(dr["primarykey"].ToString()))
							column += @"primaryKey=""true"" ";
						if(Convert.ToBoolean(dr["identity"].ToString()))
							column += @"autoIncrement=""true"" ";
						column += @"description="""" ";
						column += @"/>";
						_writer.WriteLine(column);
					}
					catch(Exception ex)
					{
						System.Windows.Forms.MessageBox.Show("Error while writing column:\n\n"+ex.Message);
						return false;
					}
				}
			}
			catch(Exception ex)
			{
				System.Windows.Forms.MessageBox.Show("Error while writing column:\n\n"+ex.Message);
				return false;
			}
			return true;
		}

		private bool WriteRelations(DataRow tablerow, string relationtype)
		{
			try
			{
				string relation = (relationtype=="foreignkey")?"foreign-key":"iforeign-key";
				foreach(DataRow dr in tablerow.GetChildRows(relationtype+"s"))
				{
					if(dr["create"].ToString().Length==0)
						dr["create"] = false;
					if(!Convert.ToBoolean(dr["create"].ToString()))
						continue;										
					string foreignkey = "\t"+"<"+relation+@" foreignTable=""#foreigntable#"" name=""#name#"" onUpdate=""#onupdate#"" onDelete=""#ondelete#"">";
					string reference = "\t\t"+@"<#reference# local=""#local#"" foreign=""#foreign#""/>";
					//Must refer to tables name ! not the javaName
					foreignkey = foreignkey.Replace("#foreigntable#",  GetForeignTableName(dr));
					if (this._generateJavaName)
					{
						foreignkey = foreignkey.Replace("#name#", GetForeignTableJavaName(dr) + "Ref");
					}
					else
					{
						foreignkey = foreignkey.Replace("#name#", ((dr["name"].ToString().Length>0)?dr["name"].ToString():dr["foreigntable"].ToString()+"Ref"));
					}
					foreignkey = foreignkey.Replace("#onupdate#", dr["onupdate"].ToString());
					foreignkey = foreignkey.Replace("#ondelete#", dr["ondelete"].ToString());
					reference  = reference.Replace("#reference#", ((relationtype=="foreignkey")?"reference":"ireference"));
					//Must refer to columns name ! not the javaName
					reference  = reference.Replace("#local#", GetLocalName(dr));
					//Must refer to columns name ! not the javaName
					reference  = reference.Replace("#foreign#", GetForeignName(dr));
					_writer.WriteLine(foreignkey);
					_writer.WriteLine(reference);
					_writer.WriteLine("\t</"+relation+">");
				}
			}
			catch(Exception ex)
			{
				System.Windows.Forms.MessageBox.Show("Error while writing column:\n\n"+ex.Message);
				return false;
			}
			return true;
		}

		private string GetForeignTableName(DataRow parentTableRow)
		{
			string select = "name = '"+parentTableRow["foreigntable"].ToString()+"'";
			DataRow[] rows = _ds.Tables["table"].Select(select);
			if(rows.Length > 0)
				//return (rows[0]["name"].ToString().Length==0)?rows[0]["javaName"].ToString():rows[0]["name"].ToString();
				return rows[0]["name"].ToString();
			else
				return "TABLE_NOT_FOUND";
		}

		private string GetForeignTableJavaName(DataRow parentTableRow)
		{
			string select = "name = '"+parentTableRow["foreigntable"].ToString()+"'";
			DataRow[] rows = _ds.Tables["table"].Select(select);
			if(rows.Length > 0)
				//return (rows[0]["name"].ToString().Length==0)?rows[0]["javaName"].ToString():rows[0]["name"].ToString();
				return rows[0]["javaName"].ToString();
			else
				return "TABLE_NOT_FOUND";
		}

		private string GetLocalName(DataRow parentTableRow)
		{
			string select = "tableid = "+parentTableRow["tableid"].ToString()+ " AND name = '"+parentTableRow["local"].ToString()+"'";
			DataRow[] rows = _ds.Tables["column"].Select(select);
			if(rows.Length > 0)
				//return (rows[0]["name"].ToString().Length==0)?rows[0]["javaName"].ToString():rows[0]["name"].ToString();
				return rows[0]["name"].ToString();
			else
				return "COLUMN_LOCAL_NOT_FOUND";
		}

		private string GetForeignName(DataRow parentTableRow)
		{
			DataRow[] rowsId = _ds.Tables["table"].Select("name ='"+parentTableRow["foreigntable"].ToString()+"'");
			if(rowsId.Length == 0)
				return "COLUMN_FOREIGN_NOT_FOUND";
			string select = "tableid = "+rowsId[0]["id"].ToString()+ " AND name = '"+parentTableRow["foreign"].ToString()+"'";
			DataRow[] rows = _ds.Tables["column"].Select(select);
			if(rows.Length > 0)
				//return (rows[0]["name"].ToString().Length==0)?rows[0]["javaName"].ToString():rows[0]["name"].ToString();
				return rows[0]["name"].ToString();
			else
				return "COLUMN_FOREIGN_NOT_FOUND";
		}

		private void WriteEndTag()
		{
			_writer.WriteLine("</database>");
		}

		private bool InitWriter()
		{
			try
			{
				string file = _ds.Tables["xml"].Rows[0]["modelpathfile"].ToString();
				_writer = new StreamWriter(file);				
			}
			catch(Exception ex)
			{
				System.Windows.Forms.MessageBox.Show("Error while writing model in private method InitWriter()!\n\nMessage:\n"+ex.Message+"\n\nMay be the path & filename you choose is empty or impossible to create ?",
					"Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
				return false;
			}
			return true;
		}

		private void CloseWriter()
		{
			if(_writer != null)
				_writer.Close();
		}

		private void SetHeader()
		{
			_header = @"<?xml version=""1.0"" encoding=""ISO-8859-1"" standalone=""no""?>";
			_header += "\n"+@"<!DOCTYPE database SYSTEM ""#norque#"">";
			_header += "\n"+@"<?neo path=""#neopath#""?>"+"\n";
			_header += "\n"+@"<database name=""#database#"" package=""#package#"" defaultJavaNamingMethod=""#javaNamingMethod#"" tablePrefix=""#tablePrefix#"" defaultIdMethod=""#idmethod#"">"+"\n\n";
			//Replacements
			_header = _header.Replace("#norque#", _ds.Tables["xml"].Rows[0]["norquedtd"].ToString());
			_header = _header.Replace("#neopath#", _ds.Tables["xml"].Rows[0]["neopath"].ToString());
			_header = _header.Replace("#database#", _ds.Tables["xml"].Rows[0]["neodbname"].ToString());
			_header = _header.Replace("#package#", _ds.Tables["xml"].Rows[0]["packagename"].ToString());
			_header = _header.Replace("#idmethod#", _ds.Tables["xml"].Rows[0]["idmethod"].ToString());
			_header = _header.Replace("#javaNamingMethod#", _ds.Tables["xml"].Rows[0]["javaNamingMethod"].ToString());
			_header = _header.Replace("#tablePrefix#", _ds.Tables["xml"].Rows[0]["tablePrefix"].ToString());
		}

		#region IWriter Member

		public bool SupportsNeo
		{
			get
			{
				return true;
			}
		}
	
		public bool GenerateJavaName
		{
			get
			{
				return _generateJavaName;
			}
			set
			{
				_generateJavaName = value;
			}
		}

		public string Abbreviation
		{
			get 
			{
				return _abbreviation;
			}
		}

		public string WriterName
		{
			get
			{
				return _name;
			}
			set
			{
				_name = value;
			}
		}

		public bool Write(System.Data.DataSet currentdataset)
		{
			_ds = currentdataset;
			if(!InitWriter())
				return false;
			if(!WriteHeader())
				return false;
			foreach(DataRow dr in _ds.Tables["table"].Rows)
			{
				if(!WriteTable(dr))
				{
					CloseWriter();
					return false;
				}
			}
			WriteEndTag();
			CloseWriter();
			return true;
		}

		#endregion
	}
}

/*
 * $Log: NeoXMLModelWriter.cs,v $
 * Revision 1.11  2005/01/12 06:36:30  larsbm
 * - Bugfixing: javaName and name were permuted
 *
 * Revision 1.10  2004/11/29 12:02:26  larsbm
 * - bugfix in writing foregein and iforeignrelations, now, foreigntable, local and foreign fields refers to the name
 * field instead of the javaName field
 *
 * Revision 1.9  2004/11/29 10:45:37  larsbm
 * - bugfix write ireference instead reference
 * - bugfix hidden was always true
 * - conversion to boolean failed
 * - set readonlys
 *
 * Revision 1.8  2004/11/24 13:57:05  larsbm
 * - new project SQLToNeoPlugIn
 * - switched interfaces from mainsource into plug in
 *
 * Revision 1.7  2004/11/24 13:16:38  larsbm
 * - extended the IWriter interface
 *
 * Revision 1.6  2004/11/09 09:01:51  larsbm
 * - Fixed bugs in NeoXmlWriter
 * - Add waitcursor while loading data
 *
 * Revision 1.5  2004/11/03 11:08:36  larsbm
 * - add name is javaName if name length is 0
 *
 * Revision 1.4  2004/11/01 14:36:33  larsbm
 * - Finished NeoXmlModelWriter
 * - Fixed bugs in TableStyleCreator and TableBuilder
 * - Implement new RestrictionChecker and additional test cases
 *
 * Revision 1.3  2004/10/29 13:49:36  larsbm
 * - work on .. last todo realize "create = false"
 *
 * Revision 1.2  2004/10/28 13:47:22  larsbm
 * - Work on ..
 *
 * Revision 1.1  2004/10/27 14:09:23  larsbm
 * - Fixed bugs in tablebuilder, TablestyleCreator
 * - Working on the forms
 * - Finishing DBTypes
 * - Add IWriter & Writer, NeoXMLModelWriter as abstraction for writing the xml model
 *
 */
